/**
 * Copyright &copy; 2015-2020 <a href="http://www.jeeplus.org/">JeePlus</a> All rights reserved.
 */
package com.jeeplus.modules.flowable.service;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.jeeplus.common.utils.StringUtils;
import com.jeeplus.core.persistence.Page;
import com.jeeplus.core.service.BaseService;
import com.jeeplus.modules.flowable.entity.Flow;
import com.jeeplus.modules.flowable.mapper.FlowMapper;
import com.jeeplus.modules.flowable.service.converter.json.FlowModelService;
import com.jeeplus.modules.flowable.utils.ProcessDefCache;
import com.jeeplus.modules.sys.entity.Role;
import com.jeeplus.modules.sys.entity.User;
import com.jeeplus.modules.sys.utils.UserUtils;
import org.apache.commons.beanutils.PropertyUtils;
import org.flowable.bpmn.model.*;
import org.flowable.bpmn.model.Process;
import org.flowable.common.engine.api.delegate.Expression;
import org.flowable.editor.language.json.converter.BpmnJsonConverter;
import org.flowable.engine.*;
import org.flowable.engine.history.HistoricActivityInstance;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.history.HistoricProcessInstanceQuery;
import org.flowable.engine.impl.RepositoryServiceImpl;
import org.flowable.engine.impl.persistence.entity.ExecutionEntity;
import org.flowable.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.flowable.engine.impl.util.ProcessDefinitionUtil;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.repository.ProcessDefinitionQuery;
import org.flowable.engine.runtime.Execution;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.engine.runtime.ProcessInstanceQuery;
import org.flowable.engine.task.Comment;
import org.flowable.image.ProcessDiagramGenerator;
import org.flowable.task.api.DelegationState;
import org.flowable.task.api.Task;
import org.flowable.task.api.TaskQuery;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.flowable.task.api.history.HistoricTaskInstanceQuery;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.*;

/**
 * 流程定义相关Service
 *
 * @author jeeplus
 * @version 2016-11-03
 */
@Service
@Transactional(readOnly = true)
public class FlowTaskService extends BaseService {

    @Autowired
    private FlowMapper flowMapper;
    @Autowired
    private RuntimeService runtimeService;
    @Autowired
    private TaskService taskService;
    @Autowired
    private FormService formService;
    @Autowired
    private HistoryService historyService;
    @Autowired
    private RepositoryService repositoryService;
    @Autowired
    private IdentityService identityService;
    @Autowired
    private FlowModelService flowModelService;

    /**
     * 获取待办任务列表
     *
     * @return
     */
    public Page<HashMap<String, String>> todoList(Page<HashMap<String, String>> page, Flow flow) {
        List<HashMap<String, String>> result = new ArrayList<HashMap<String, String>> ();
        String userId = UserUtils.getUser ().getId ();//ObjectUtils.toString(UserUtils.getUser().getId());
        // =============== 已经签收的任务  ===============
        TaskQuery todoTaskQuery = taskService.createTaskQuery ().taskAssignee (userId).active ()
                .includeProcessVariables ().orderByTaskCreateTime ().desc ();

        // 设置查询条件
        if (StringUtils.isNotBlank (flow.getProcDefKey ())) {
            todoTaskQuery.processDefinitionKey (flow.getProcDefKey ());
        }
        if (flow.getBeginDate () != null) {
            todoTaskQuery.taskCreatedAfter (flow.getBeginDate ());
        }
        if (flow.getEndDate () != null) {
            todoTaskQuery.taskCreatedBefore (flow.getEndDate ());
        }
        if(StringUtils.isNotBlank (flow.getTitle ())){
            todoTaskQuery.processVariableValueLike ("title", "%"+flow.getTitle ()+"%");
        }

        // =============== 等待签收的任务  ===============
        List<Role> roleList = UserUtils.getRoleList ();
        List<String> roles = Lists.newArrayList ();
        for (Role role : roleList) {
            roles.add (role.getId ());
        }
        TaskQuery toClaimQuery = taskService.createTaskQuery ().taskCandidateGroupIn (roles).taskCandidateUser (userId)
                .includeProcessVariables ().active ().orderByTaskCreateTime ().desc ();


        // 设置查询条件
        if (StringUtils.isNotBlank (flow.getProcDefKey ())) {
            toClaimQuery.processDefinitionKey (flow.getProcDefKey ());
        }
        if (flow.getBeginDate () != null) {
            toClaimQuery.taskCreatedAfter (flow.getBeginDate ());
        }
        if (flow.getEndDate () != null) {
            toClaimQuery.taskCreatedBefore (flow.getEndDate ());
        }
        if(StringUtils.isNotBlank (flow.getTitle ())){
            toClaimQuery.processVariableValueLike ("title", "%"+flow.getTitle ()+"%");
        }
        long taskCount = todoTaskQuery.count ();
        long claimCount = toClaimQuery.count ();
        long total = taskCount + claimCount;
        page.setCount (total);


        int start = page.getFirstResult ();
        int end = page.getFirstResult () + page.getMaxResults ();
        // 查询列表
        List<Task> todoList = Lists.newArrayList ();
        // 查询列表
        List<Task> toClaimList = Lists.newArrayList ();
        if (end == -1) {//不分页
            todoList = todoTaskQuery.list ();
            toClaimList = toClaimQuery.list ();
        } else {

            if (end <= taskCount) {
                todoList = todoTaskQuery.listPage (start, page.getMaxResults ());
            } else if (start < taskCount) {
                todoList = todoTaskQuery.listPage (start, (int) taskCount - start);
                toClaimList = toClaimQuery.listPage (0, end - (int) taskCount);
            } else {
                toClaimList = toClaimQuery.listPage (start - (int) taskCount, page.getMaxResults ());
            }
        }

        for (Task task : toClaimList) {
            HashMap map = new HashMap ();
            HashMap taskMap = new HashMap ();
            HashMap procDefMap = new HashMap ();
            taskMap.put ("assignee", task.getAssignee ());
            taskMap.put ("id", task.getId ());
            taskMap.put ("name", task.getName ());
            taskMap.put ("createTime", task.getCreateTime ());
            taskMap.put ("executionId", task.getExecutionId ());
            taskMap.put ("processInstanceId", task.getProcessInstanceId ());
            taskMap.put ("processDefinitionId", task.getProcessDefinitionId ());
            taskMap.put ("taskDefinitionKey", task.getTaskDefinitionKey ());
            map.put ("task", taskMap);
            map.put ("vars", task.getProcessVariables ());
            procDefMap.put ("name", ProcessDefCache.get (task.getProcessDefinitionId ()).getName ());
            procDefMap.put ("version", ProcessDefCache.get (task.getProcessDefinitionId ()).getVersion ());
            map.put ("procDef", procDefMap);
            map.put ("status", "claim");
            page.getList ().add (map);
        }

        for (Task task : todoList) {
            HashMap map = new HashMap ();
            HashMap taskMap = new HashMap ();
            HashMap procDefMap = new HashMap ();
            taskMap.put ("assignee", task.getAssignee ());
            taskMap.put ("id", task.getId ());
            taskMap.put ("createTime", task.getCreateTime ());
            taskMap.put ("name", task.getName ());
            taskMap.put ("executionId", task.getExecutionId ());
            taskMap.put ("processDefinitionId", task.getProcessDefinitionId ());
            taskMap.put ("processInstanceId", task.getProcessInstanceId ());
            taskMap.put ("taskDefinitionKey", task.getTaskDefinitionKey ());
            map.put ("task", taskMap);
            map.put ("vars", task.getProcessVariables ());
            procDefMap.put ("name", ProcessDefCache.get (task.getProcessDefinitionId ()).getName ());
            procDefMap.put ("version", ProcessDefCache.get (task.getProcessDefinitionId ()).getVersion ());
            map.put ("procDef", procDefMap);
            map.put ("status", "todo");
            map.put ("claimTime", task.getClaimTime ());
            page.getList ().add (map);
        }


        return page;

    }

    /**
     * 获取已办任务列表
     *
     * @param page
     * @return
     */
    public Page<HashMap<String, String>> historicList(Page<HashMap<String, String>> page, Flow act) {
        String userId = UserUtils.getUser ().getId ();//ObjectUtils.toString(UserUtils.getUser().getId());

        HistoricTaskInstanceQuery histTaskQuery = historyService.createHistoricTaskInstanceQuery ().taskAssignee (userId).finished ()
                .includeProcessVariables ().orderByHistoricTaskInstanceEndTime ().desc ();

        // 设置查询条件
        if (StringUtils.isNotBlank (act.getProcDefKey ())) {
            histTaskQuery.processDefinitionKey (act.getProcDefKey ());
        }
        if (act.getBeginDate () != null) {
            histTaskQuery.taskCompletedAfter (act.getBeginDate ());
        }
        if (act.getEndDate () != null) {
            histTaskQuery.taskCompletedBefore (act.getEndDate ());
        }
        if(act.getTitle () != null){
            histTaskQuery.processVariableValueLike ("title", "%"+act.getTitle ()+"%");
        }

        // 查询总数
        page.setCount (histTaskQuery.count ());
        page.initialize ();

        // 查询列表
        List<HistoricTaskInstance> histList = Lists.newArrayList ();
        if (page.getMaxResults () == -1) {
            histList = histTaskQuery.list ();
        } else {
            histList = histTaskQuery.listPage (page.getFirstResult (), page.getMaxResults ());
        }

        for (HistoricTaskInstance histTask : histList) {
            HashMap map = new HashMap ();
            HashMap taskMap = new HashMap ();
            HashMap procDefMap = new HashMap ();
            taskMap.put ("assignee", histTask.getAssignee ());
            taskMap.put ("id", histTask.getId ());
            taskMap.put ("name", histTask.getName ());
            taskMap.put ("endTime", histTask.getEndTime ());
            taskMap.put ("executionId", histTask.getExecutionId ());
            ;
            taskMap.put ("taskDefinitionKey", histTask.getTaskDefinitionKey ());
            map.put ("task", taskMap);
            map.put ("vars", histTask.getProcessVariables ());
            procDefMap.put ("processInstanceId", histTask.getProcessInstanceId ());
            procDefMap.put ("processDefinitionId", histTask.getProcessDefinitionId ());
            procDefMap.put ("name", ProcessDefCache.get (histTask.getProcessDefinitionId ()).getName ());
            procDefMap.put ("version", ProcessDefCache.get (histTask.getProcessDefinitionId ()).getVersion ());
            map.put ("proc", procDefMap);
            map.put ("isBack", isBack (histTask));
            try {
                map.putAll (queryProcessState (histTask.getProcessInstanceId ()));
            } catch (Exception e1) {
                e1.printStackTrace ();
            }

            page.getList ().add (map);
        }
        return page;
    }

    /**
     * 获取流转历史任务列表
     *
     * @param procInsId 流程实例
     * @param startFlow 开始活动节点名称
     * @param endFlow   结束活动节点名称
     */
    public List<Flow> histoicFlowList(String procInsId, String startFlow, String endFlow) {
        List<Flow> actList = Lists.newArrayList ();
        List<HistoricActivityInstance> list = Lists.newArrayList ();
        List<HistoricActivityInstance> historicActivityInstances2 = historyService.createHistoricActivityInstanceQuery ().processInstanceId (procInsId)
                .orderByHistoricActivityInstanceStartTime ().asc ().orderByHistoricActivityInstanceEndTime ().asc ().list ();
        ;
        for (HistoricActivityInstance historicActivityInstance : historicActivityInstances2) {
            if (historicActivityInstance.getEndTime () != null) {
                list.add (historicActivityInstance);
            }
        }

        for (HistoricActivityInstance historicActivityInstance : historicActivityInstances2) {
            if (historicActivityInstance.getEndTime () == null) {
                list.add (historicActivityInstance);
            }
        }
        boolean start = false;
        Map<String, Integer> actMap = Maps.newHashMap ();

        for (int i = 0; i < list.size (); i++) {

            HistoricActivityInstance histIns = list.get (i);

            // 过滤开始节点前的节点
            if (StringUtils.isNotBlank (startFlow) && startFlow.equals (histIns.getActivityId ())) {
                start = true;
            }
            if (StringUtils.isNotBlank (startFlow) && !start) {
                continue;
            }

            // 只显示开始节点和结束节点，并且执行人不为空的任务
            if (StringUtils.isNotBlank (histIns.getAssignee ())
                    || "startEvent".equals (histIns.getActivityType ())
                    || "endEvent".equals (histIns.getActivityType ())) {

                // 给节点增加一个序号
                Integer actNum = actMap.get (histIns.getActivityId ());
                if (actNum == null) {
                    actMap.put (histIns.getActivityId (), actMap.size ());
                }

                Flow e = new Flow ();
                e.setHistIns (histIns);
                // 获取流程发起人名称
                if ("startEvent".equals (histIns.getActivityType ())) {
                    List<HistoricProcessInstance> il = historyService.createHistoricProcessInstanceQuery ().processInstanceId (procInsId).orderByProcessInstanceStartTime ().asc ().list ();
                    if (il.size () > 0) {
                        if (StringUtils.isNotBlank (il.get (0).getStartUserId ())) {
                            User user = UserUtils.get (il.get (0).getStartUserId ());
                            if (user != null) {
                                e.setAssignee (histIns.getAssignee ());
                                e.setAssigneeName (user.getName ());
                            }
                        }
                    }
                    e.setComment ("【创建流程】");
                }
                if ("endEvent".equals (histIns.getActivityType ())) {
                    e.setComment ("【结束流程】");
                }
                // 获取任务执行人名称
                if (StringUtils.isNotEmpty (histIns.getAssignee ())) {
                    User user = UserUtils.get (histIns.getAssignee ());
                    if (user != null) {
                        e.setAssignee (histIns.getAssignee ());
                        e.setAssigneeName (user.getName ());
                    }
                }
                // 获取意见评论内容
                if (StringUtils.isNotBlank (histIns.getTaskId ())) {
                    List<Comment> commentList = taskService.getTaskComments (histIns.getTaskId ());
                    if (commentList.size () > 0) {
                        e.setComment (commentList.get (0).getFullMessage ());
                    }
                }
                if (historyService.createHistoricTaskInstanceQuery ().taskId (histIns.getTaskId ()).count () == 0) {
                    e.setComment ("【用户撤回】");
                }
                actList.add (e);
            }

            // 过滤结束节点后的节点
            if (StringUtils.isNotBlank (endFlow) && endFlow.equals (histIns.getActivityId ())) {
                boolean bl = false;
                Integer actNum = actMap.get (histIns.getActivityId ());
                // 该活动节点，后续节点是否在结束节点之前，在后续节点中是否存在
                for (int j = i + 1; j < list.size (); j++) {
                    HistoricActivityInstance hi = list.get (j);
                    Integer actNumA = actMap.get (hi.getActivityId ());
                    if ((actNumA != null && actNumA < actNum) || StringUtils.equals (hi.getActivityId (), histIns.getActivityId ())) {
                        bl = true;
                    }
                }
                if (!bl) {
                    break;
                }
            }
        }
        return actList;
    }

    /**
     * 获取流程定义列表
     *
     * @param category 流程分类
     */
    public Page<Object[]> processList(Page<Object[]> page, String category) {
        /*
         * 保存两个对象，一个是ProcessDefinition（流程定义），一个是Deployment（流程部署）
         */
        ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery ()
                .latestVersion ().active ().orderByProcessDefinitionKey ().asc ();

        if (StringUtils.isNotEmpty (category)) {
            processDefinitionQuery.processDefinitionCategory (category);
        }

        page.setCount (processDefinitionQuery.count ());
        List<ProcessDefinition> processDefinitionList = Lists.newArrayList ();
        if (page.getMaxResults () == -1) {//不分页
            processDefinitionList = processDefinitionQuery.list ();
        } else {
            processDefinitionList = processDefinitionQuery.listPage (page.getFirstResult (), page.getMaxResults ());
        }
        for (ProcessDefinition processDefinition : processDefinitionList) {
            String deploymentId = processDefinition.getDeploymentId ();
            Deployment deployment = repositoryService.createDeploymentQuery ().deploymentId (deploymentId).singleResult ();
            page.getList ().add (new Object[]{processDefinition, deployment});
        }
        return page;
    }

    /**
     * 获取流程表单（首先获取任务节点表单KEY，如果没有则取流程开始节点表单KEY）
     *
     * @return
     */
    public String getFormKey(String procDefId, String taskDefKey) {
        String formKey = "";
        if (StringUtils.isNotBlank (procDefId)) {
            if (StringUtils.isNotBlank (taskDefKey)) {
                try {
                    formKey = formService.getTaskFormKey (procDefId, taskDefKey);
                } catch (Exception e) {
                    formKey = "";
                }
            }
            if (StringUtils.isBlank (formKey)) {
                formKey = formService.getStartFormKey (procDefId);
            }
            if (StringUtils.isBlank (formKey)) {
                formKey = "/404";
            }
        }
        logger.debug ("getFormKey: {}", formKey);
        return formKey;
    }

    /**
     * 获取正在运行的流程实例对象
     *
     * @param procInsId
     * @return
     */
    @Transactional(readOnly = false)
    public ProcessInstance getProcIns(String procInsId) {
        return runtimeService.createProcessInstanceQuery ().processInstanceId (procInsId).singleResult ();
    }

    /**
     * 获取已经结束流程实例对象
     *
     * @param procInsId
     * @return
     */
    @Transactional(readOnly = false)
    public HistoricProcessInstance getFinishedProcIns(String procInsId) {
        return historyService.createHistoricProcessInstanceQuery ().processInstanceId (procInsId).singleResult ();
    }


    /**
     * 获取正在运行的流程实例对象列表
     *
     * @param procDefKey
     * @return
     */
    @Transactional(readOnly = false)
    public List<ProcessInstance> getRunngingProcIns(String procDefKey, User user, int[] pageParams) {
        ProcessInstanceQuery query = runtimeService.createProcessInstanceQuery ().processDefinitionKey (procDefKey).active ().orderByProcessInstanceId ().desc ();
        List<ProcessInstance> list = new ArrayList<ProcessInstance> ();
        if (User.isAdmin (user.getId ())) {
            list = query.listPage (pageParams[0], pageParams[1]);
        } else {
            list = query.involvedUser (user.getId ()).listPage (pageParams[0], pageParams[1]);
        }
        return list;
    }


    /**
     * 获取已经结束的流程实例对象列表
     *
     * @param procDefKey
     * @return
     */
    @Transactional(readOnly = false)
    public List<HistoricProcessInstance> getFinishedProcIns(String procDefKey, User user, int[] pageParams) {
        HistoricProcessInstanceQuery query = historyService.createHistoricProcessInstanceQuery ().processDefinitionKey (procDefKey).finished ().orderByProcessInstanceEndTime ().desc ();
        List<HistoricProcessInstance> list = new ArrayList<HistoricProcessInstance> ();
        if (User.isAdmin (user.getId ())) {
            list = query.listPage (pageParams[0], pageParams[1]);
        } else {
            list = query.involvedUser (user.getId ()).listPage (pageParams[0], pageParams[1]);
        }
        return list;
    }

    /**
     * 获取我发起的流程申请列表
     *
     * @param user
     * @return
     */
    @Transactional(readOnly = false)
    public Page<HashMap> getMyStartedProcIns(User user, Page<HashMap> page, Flow flow) throws Exception {
        HistoricProcessInstanceQuery query = historyService.createHistoricProcessInstanceQuery ().startedBy (user.getId ()).includeProcessVariables ().orderByProcessInstanceStartTime ().desc ();
        if (flow.getBeginDate () != null) {
            query.startedAfter (flow.getBeginDate ());
        }
        if (flow.getEndDate () != null) {
            query.startedBefore (flow.getEndDate ());
        }
        if(StringUtils.isNotBlank (flow.getTitle ())){
            query.variableValueLike ("title","%"+flow.getTitle ()+"%");
        }

        page.setCount (query.count ());
        List<HistoricProcessInstance> histList = Lists.newArrayList ();
        if (page.getMaxResults () == -1) {//不分页
            histList = query.list ();
        } else {
            histList = query.involvedUser (user.getId ()).listPage (page.getFirstResult (), page.getMaxResults ());
        }
        for (HistoricProcessInstance historicProcessInstance : histList) {

            HashMap map = new HashMap ();
            Map state = queryProcessState (historicProcessInstance.getId ());
            HashMap procInsMap = new HashMap ();
            HashMap procDefMap = new HashMap ();
            procInsMap.put ("endTime", historicProcessInstance.getEndTime ());
            procInsMap.put ("startTime", historicProcessInstance.getStartTime ());
            procInsMap.put ("processInstanceId", historicProcessInstance.getId ());
            procDefMap.put ("processDefinitionId", historicProcessInstance.getProcessDefinitionId ());
            map.put ("vars", historicProcessInstance.getProcessVariables ());
            procDefMap.put ("name", historicProcessInstance.getProcessDefinitionName ());
            procDefMap.put ("version", historicProcessInstance.getProcessDefinitionVersion ());
            procInsMap.putAll (state);
            map.put ("procDef", procDefMap);
            map.put ("procIns", procInsMap);
            page.getList ().add (map);
        }

        return page;
    }

    /**
     * 启动流程
     *
     * @param procDefKey    流程定义KEY
     * @param businessTable 业务表表名
     * @param businessId    业务表编号
     * @return 流程实例ID
     */
    @Transactional(readOnly = false)
    public String startProcess(String procDefKey, String businessTable, String businessId) {
        return startProcess (procDefKey, businessTable, businessId, "");
    }

    /**
     * 启动流程
     *
     * @param procDefKey    流程定义KEY
     * @param businessTable 业务表表名
     * @param businessId    业务表编号
     * @param title         流程标题，显示在待办任务标题
     * @return 流程实例ID
     */
    @Transactional(readOnly = false)
    public String startProcess(String procDefKey, String businessTable, String businessId, String title) {
        Map<String, Object> vars = Maps.newHashMap ();
        return startProcess (procDefKey, businessTable, businessId, title, vars);
    }

    /**
     * 启动流程
     *
     * @param procDefKey    流程定义KEY
     * @param businessTable 业务表表名
     * @param businessId    业务表编号
     * @param title         流程标题，显示在待办任务标题
     * @param vars          流程变量
     * @return 流程实例ID
     */
    @SuppressWarnings("unused")
    @Transactional(readOnly = false)
    public String startProcess(String procDefKey, String businessTable, String businessId, String title, Map<String, Object> vars) {
        //String userId = UserUtils.getUser().getLoginName();//ObjectUtils.toString(UserUtils.getUser().getId())
        // 设置流程变量
        if (vars == null) {
            vars = Maps.newHashMap ();
        }

        String userId = (String) vars.get ("applyUserId");
        if (userId == null) {
            userId = UserUtils.getUser ().getId ();
        }
        String userName = UserUtils.get (userId).getName ();
        vars.put ("userName", userName);

        // 用来设置启动流程的人员ID，引擎会自动把用户ID保存到activiti:initiator中
        identityService.setAuthenticatedUserId (userId);

        // 设置流程标题
        if (StringUtils.isNotBlank (title)) {
            vars.put ("title", title);
        }

        // 启动流程
        ProcessInstance procIns = runtimeService.startProcessInstanceByKey (procDefKey, businessTable + ":" + businessId, vars);

        // 更新业务表流程实例ID
        Flow act = new Flow ();
        act.setBusinessTable (businessTable);// 业务表名
        act.setBusinessId (businessId);  // 业务表ID
        act.setProcInsId (procIns.getId ());
        act.setVars (vars);
        flowMapper.updateProcInsIdByBusinessId (act);
        return act.getProcInsId ();
    }

    /**
     * 获取任务
     *
     * @param taskId 任务ID
     */
    public Task getTask(String taskId) {
        return taskService.createTaskQuery ().taskId (taskId).singleResult ();
    }

    /**
     * 删除任务
     *
     * @param taskId       任务ID
     * @param deleteReason 删除原因
     */
    public void deleteTask(String taskId, String deleteReason) {
        taskService.deleteTask (taskId, deleteReason);
    }

    /**
     * 签收任务
     *
     * @param taskId 任务ID
     * @param userId 签收用户ID（用户登录名）
     */
    @Transactional(readOnly = false)
    public void claim(String taskId, String userId) {
        taskService.claim (taskId, userId);
    }


    /**
     * 提交任务, 并保存意见
     *
     * @param taskId    任务ID
     * @param procInsId 流程实例ID，如果为空，则不保存任务提交意见
     * @param comment   任务提交意见的内容
     * @param vars      任务变量
     */
    @Transactional(readOnly = false)
    public void complete(String taskId, String procInsId, String comment, Map<String, Object> vars) {
        complete (taskId, procInsId, comment, "", vars);
    }

    /**
     * 提交任务, 并保存意见
     *
     * @param taskId    任务ID
     * @param procInsId 流程实例ID，如果为空，则不保存任务提交意见
     * @param comment   任务提交意见的内容
     * @param title     流程标题，显示在待办任务标题
     * @param vars      任务变量
     */
    @Transactional(readOnly = false)
    public void complete(String taskId, String procInsId, String comment, String title, Map<String, Object> vars) {
        // 添加意见
        if (StringUtils.isNotBlank (procInsId) && StringUtils.isNotBlank (comment)) {
            taskService.addComment (taskId, procInsId, comment);
        }

        // 设置流程变量
        if (vars == null) {
            vars = Maps.newHashMap ();
        }

        // 设置流程标题
        if (StringUtils.isNotBlank (title)) {
            vars.put ("title", title);
        }


        Task task = taskService.createTaskQuery ().taskId (taskId).singleResult ();
        // owner不为空说明可能存在委托任务
        if (StringUtils.isNotBlank (task.getOwner ())) {
            DelegationState delegationState = task.getDelegationState ();
            switch (delegationState) {
                case PENDING:
                    taskService.resolveTask (taskId);
                    taskService.complete (taskId, vars);
                    break;

                case RESOLVED:
                    // 委托任务已经完成
                    break;

                default:
                    // 不是委托任务
                    taskService.complete (taskId, vars);
                    break;
            }
        } else {
            // 提交任务
            taskService.complete (taskId, vars);
        }
    }

    /**
     * 完成第一个任务
     *
     * @param procInsId
     */
    public void completeFirstTask(String procInsId) {
        completeFirstTask (procInsId, null, null, null);
    }

    /**
     * 完成第一个任务
     *
     * @param procInsId
     * @param comment
     * @param title
     * @param vars
     */
    public void completeFirstTask(String procInsId, String comment, String title, Map<String, Object> vars) {
        String userId = UserUtils.getUser ().getId ();
        Task task = taskService.createTaskQuery ().taskAssignee (userId).processInstanceId (procInsId).active ().singleResult ();
        if (task != null) {
            complete (task.getId (), procInsId, comment, title, vars);
        }
    }

    /**
     * 查询流程实例状态
     *
     * @param processInstanceId
     * @return
     * @throws Exception
     */
    public Map queryProcessState(String processInstanceId) throws Exception {
        Map map = new HashMap ();
        // 通过流程实例ID查询流程实例
        ProcessInstance pi = runtimeService.createProcessInstanceQuery ()
                .processInstanceId (processInstanceId).singleResult ();
        if (pi != null) {
            if (pi.isSuspended ()) {
                //执行实例
                map.put ("code", 0);
                map.put ("status", "已挂起");
                return map;
            } else {
                //执行实例
                map.put ("code", 1);
                map.put ("status", "运行中");
                Task currentTask = taskService.createTaskQuery ().processInstanceId (processInstanceId).singleResult ();
                HashMap taskMap = new HashMap ();
                taskMap.put ("assignee", currentTask.getAssignee ());
                taskMap.put ("id", currentTask.getId ());
                taskMap.put ("name", currentTask.getName ());
                taskMap.put ("executionId", currentTask.getExecutionId ());
                taskMap.put ("taskDefinitionKey", currentTask.getTaskDefinitionKey ());
                map.put ("currentTask", taskMap);
                return map;
            }

        } else {
            HistoricProcessInstance pi2 = historyService.createHistoricProcessInstanceQuery ().processInstanceId (processInstanceId).singleResult ();
            if (pi2 != null) {
                if (pi2.getDeleteReason () == null) {
                    map.put ("code", 2);
                    map.put ("status", "正常结束");
                    return map;
                } else if (pi2.getDeleteReason ().equals ("用户撤销")) {
                    map.put ("code", 3);
                    map.put ("status", "用户撤销");
                    return map;
                } else {
                    map.put ("code", 4);
                    map.put ("status", "流程作废");
                    map.put ("deleteReason", pi2.getDeleteReason ());
                    return map;
                }

            } else {
                map.put ("code", 5);
                map.put ("status", "已删除");
                map.put ("deleteReason", pi2.getDeleteReason ());
                return map;
            }

        }
    }

    /**
     * 终止流程实例
     *
     * @param processInstanceId
     */
    public void endProcessInstance(String processInstanceId, String deleteReason) throws Exception {
        runtimeService.deleteProcessInstance (processInstanceId, deleteReason);
    }


    public ProcessEngine processEngine() {
        return ProcessEngines.getDefaultProcessEngine ();
    }

    public Map getDiagram(String processId, HttpServletResponse response) {
        Map m = new HashMap ();
        try {
//    Model modelData = repositoryService.getModel(id);
//    org.flowable.ui.modeler.domain.Model modelData = flowModelService.getModel(id);
            String processDefId = "";
            ProcessInstance pi = runtimeService.createProcessInstanceQuery ().processInstanceId (processId).singleResult ();
            //流程走完的不显示图
            if (pi == null) {
                processDefId = historyService.createHistoricProcessInstanceQuery ().processInstanceId (processId).singleResult ().getProcessDefinitionId ();
            } else {
                processDefId = pi.getProcessDefinitionId ();
            }
            BpmnModel bpmnModel = repositoryService.getBpmnModel (processDefId);
            List<HistoricActivityInstance> historyProcess = getHistoryProcess (processId);
            List<String> activityIds = new ArrayList<> ();
            List<String> flows = new ArrayList<> ();
            for (HistoricActivityInstance hi : historyProcess) {
                String activityType = hi.getActivityType ();
                if (activityType.equals ("sequenceFlow") || activityType.equals ("exclusiveGateway")) {
                    flows.add (hi.getActivityId ());
                } else if (activityType.equals ("userTask") || activityType.equals ("startEvent") || activityType.equals ("endEvent")) {
                    activityIds.add (hi.getActivityId ());
                }
            }
            List<Task> tasks = taskService.createTaskQuery ().processInstanceId (processId).list ();
            for (Task task : tasks) {
                activityIds.add (task.getTaskDefinitionKey ());
            }
            byte[] bpmnBytes = flowModelService.getBpmnXML (bpmnModel);
            m.put ("bpmnXml", new String (bpmnBytes));
            m.put ("flows", flows);
            m.put ("activityIds", activityIds);
            return m;
        } catch (Exception e) {
            e.printStackTrace ();
        }
        return null;
    }

    public void tracePhoto(HttpServletResponse httpServletResponse, String processId) throws Exception {
        String processDefId = "";
        ProcessInstance pi = runtimeService.createProcessInstanceQuery ().processInstanceId (processId).singleResult ();
        //流程走完的不显示图
        if (pi == null) {
            processDefId = historyService.createHistoricProcessInstanceQuery ().processInstanceId (processId).singleResult ().getProcessDefinitionId ();
        } else {
            processDefId = pi.getProcessDefinitionId ();
        }

        List<HistoricActivityInstance> historyProcess = getHistoryProcess (processId);
        List<String> activityIds = new ArrayList<> ();
        List<String> flows = new ArrayList<> ();
        //获取流程图
        BpmnModel bpmnModel = repositoryService.getBpmnModel (processDefId);
        for (HistoricActivityInstance hi : historyProcess) {
            String activityType = hi.getActivityType ();
            if (activityType.equals ("sequenceFlow") || activityType.equals ("exclusiveGateway")) {
                flows.add (hi.getActivityId ());
            } else if (activityType.equals ("userTask") || activityType.equals ("startEvent")) {
                activityIds.add (hi.getActivityId ());
            }
        }
        List<Task> tasks = taskService.createTaskQuery ().processInstanceId (processId).list ();
        for (Task task : tasks) {
            activityIds.add (task.getTaskDefinitionKey ());
        }
        ProcessEngineConfiguration engConf = processEngine ().getProcessEngineConfiguration ();
        //定义流程画布生成器
        ProcessDiagramGenerator processDiagramGenerator = engConf.getProcessDiagramGenerator ();
        InputStream in = processDiagramGenerator.generateDiagram (bpmnModel, "png", activityIds, flows, engConf.getActivityFontName (), engConf.getLabelFontName (), engConf.getAnnotationFontName (), engConf.getClassLoader (), 1.0, true);
        OutputStream out = null;
        byte[] buf = new byte[1024];
        int legth = 0;
        try {
            out = httpServletResponse.getOutputStream ();
            while ((legth = in.read (buf)) != -1) {
                out.write (buf, 0, legth);
            }
        } finally {
            if (in != null) {
                in.close ();
            }
            if (out != null) {
                out.close ();
            }
        }


    }

    /**
     * 任务历史
     *
     * @param processId 部署id
     */
    public List<HistoricActivityInstance> getHistoryProcess(String processId) {
        List<HistoricActivityInstance> list = historyService // 历史相关Service
                .createHistoricActivityInstanceQuery () // 创建历史活动实例查询
                .processInstanceId (processId) // 执行流程实例id
                .finished ().orderByHistoricActivityInstanceEndTime ().asc ()
                .list ();
        return list;
    }


    /**
     * 获取任务节点
     *
     * @param node   查询节点选择
     * @param taskId 任务id
     */
    public FlowElement nextFlowNode(String node, String taskId) {
        Task task = taskService.createTaskQuery ().taskId (taskId).singleResult ();
        ExecutionEntity ee = (ExecutionEntity) runtimeService.createExecutionQuery ()
                .executionId (task.getExecutionId ()).singleResult ();
        // 当前审批节点
        String crruentActivityId = ee.getActivityId ();
        BpmnModel bpmnModel = repositoryService.getBpmnModel (task.getProcessDefinitionId ());
        FlowNode flowNode = (FlowNode) bpmnModel.getFlowElement (crruentActivityId);
        // 输出连线
        List<SequenceFlow> outFlows = flowNode.getOutgoingFlows ();
        for (SequenceFlow sequenceFlow : outFlows) {
            //当前审批节点
            if ("now".equals (node)) {
                FlowElement sourceFlowElement = sequenceFlow.getSourceFlowElement ();
                return (FlowNode) sourceFlowElement;
            } else if ("next".equals (node)) {
                // 下一个审批节点
                FlowElement targetFlow = sequenceFlow.getTargetFlowElement ();
                return (FlowNode) targetFlow;
            }


        }
        return null;
    }

    /**
     * 流程跟踪图信息
     *
     * @param processInstanceId 流程实例ID
     * @return 封装了各种节点信息
     */
    public List<Map<String, Object>> traceProcess(String processInstanceId) throws Exception {
        Execution execution = runtimeService.createExecutionQuery ().executionId (processInstanceId).singleResult ();//执行实例
        Object property = PropertyUtils.getProperty (execution, "activityId");
        String activityId = "";
        if (property != null) {
            activityId = property.toString ();
        }
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery ().processInstanceId (processInstanceId)
                .singleResult ();
        ProcessDefinitionEntity processDefinition = (ProcessDefinitionEntity) ((RepositoryServiceImpl) repositoryService)
                .getDeployedProcessDefinition (processInstance.getProcessDefinitionId ());
        Collection<FlowElement> activitiList = ProcessDefinitionUtil.getProcess (processInstanceId).getFlowElements ();//获得当前任务的所有节点

        List<Map<String, Object>> activityInfos = new ArrayList<Map<String, Object>> ();
        for (FlowElement activity : activitiList) {

            boolean currentActiviti = false;
            String id = activity.getId ();

            // 当前节点
            if (id.equals (activityId)) {
                currentActiviti = true;
            }

        }

        return activityInfos;
    }


    /**
     * 设置任务组
     *
     * @param vars
     * @param candidateGroupIdExpressions
     */
    private void setTaskGroup(Map<String, Object> vars, Set<Expression> candidateGroupIdExpressions) {
        String roles = "";
        for (Expression expression : candidateGroupIdExpressions) {
            String expressionText = expression.getExpressionText ();
            String roleName = identityService.createGroupQuery ().groupId (expressionText).singleResult ().getName ();
            roles += roleName;
        }
        vars.put ("任务所属角色", roles);
    }

    /**
     * 设置当前处理人信息
     *
     * @param vars
     * @param currentTask
     */
    private void setCurrentTaskAssignee(Map<String, Object> vars, Task currentTask) {
        String assignee = currentTask.getAssignee ();
        if (assignee != null) {
            org.flowable.idm.api.User assigneeUser = identityService.createUserQuery ().userId (assignee).singleResult ();
            String userInfo = assigneeUser.getFirstName () + " " + assigneeUser.getLastName ();
            vars.put ("当前处理人", userInfo);
        }
    }


    /**
     * 保存审核意见
     *
     * @param act
     */
    @Transactional(readOnly = false)
    public void auditSave(Flow act, Map vars) {
        act.preUpdate ();
        String taskDefKey = act.getTaskDefKey ();
        complete (act.getTaskId (), act.getProcInsId (), act.getComment (), vars);

    }


    /**
     * 是否可以回退
     */
    public boolean isBack(HistoricTaskInstance hisTask) {
        ProcessInstance pi = runtimeService.createProcessInstanceQuery ()
                .processInstanceId (hisTask.getProcessInstanceId ()).singleResult ();
        if (pi != null) {
            if (pi.isSuspended ()) {
                return false;
            } else {
                Task currentTask = taskService.createTaskQuery ().processInstanceId (hisTask.getProcessInstanceId ()).singleResult ();
                HistoricTaskInstance lastHisTask = historyService.createHistoricTaskInstanceQuery ().processInstanceId (hisTask.getProcessInstanceId ()).finished ()
                        .includeProcessVariables ().orderByHistoricTaskInstanceEndTime ().desc ().list ().get (0);

                if (currentTask.getClaimTime () != null) {//用户已签收
                    return false;
                }
                if (hisTask.getId ().equals (lastHisTask.getId ())) {
                    return true;
                }
                return false;
            }

        } else {
            return false;
        }


    }

}
